package org.koin.core;

import org.junit.Assert;
import org.junit.Test;
import org.koin.Simple;
import org.koin.core.context.DefaultContextExt;
import org.koin.core.definition.Definition;
import org.koin.core.error.*;
import org.koin.core.parameter.DefinitionParameters;
import org.koin.core.parameter.ParametersDefinition;
import org.koin.core.qualifier.Qualifier;
import org.koin.core.scope.Scope;
import org.koin.dsl.KoinAppDeclaration;
import org.koin.dsl.KoinApplication;
import org.koin.dsl.*;

import java.util.Arrays;
import java.util.List;

public class ClosedScopeAPI {

    String scopeName = "MY_SCOPE";

    @Test
    public void get_definition_from_current_scopes_type() {
        try {
            org.koin.core.KoinApplication koinApplication = KoinApplication.koinApplication(new KoinAppDeclaration() {
                @Override
                public void invoke(org.koin.core.KoinApplication koinApplication) {
                    koinApplication.printLogger();
                    try {
                        koinApplication.modules(Module.module(new ModuleDeclaration() {
                            @Override
                            public void invoke(org.koin.core.module.Module module) {
                                module.scope(Qualifier.named(ScopeType.class), new org.koin.core.module.Module.ScopeSet() {
                                    @Override
                                    public void invoke(ScopeDSL scopeDSL) {
                                        try {
                                            scopeDSL.scoped(Simple.ComponentA.class, null, false, new Definition<Simple.ComponentA>() {
                                                @Override
                                                public Simple.ComponentA invoke(Scope scope, DefinitionParameters parameters) {
                                                    return new Simple.ComponentA();
                                                }
                                            });
                                        } catch (DefinitionOverrideException e) {
                                            e.printStackTrace();
                                        }
                                    }
                                });
                            }
                        }));
                    } catch (DefinitionOverrideException e) {
                        e.printStackTrace();
                    }
                }
            });
            Koin koin = koinApplication.getKoin();

            Scope scope1 = koin.createScope("scope1", Qualifier.named(ScopeType.class), null);
            Scope scope2 = koin.createScope("scope2", Qualifier.named(ScopeType.class), null);

            Assert.assertNotEquals(scope1.get(Simple.ComponentA.class), scope2.get(Simple.ComponentA.class));

        } catch (ScopeAlreadyCreatedException e) {
            e.printStackTrace();
        } catch (NoScopeDefFoundException e) {
            e.printStackTrace();
        } catch (ClosedScopeException e) {
            e.printStackTrace();
        } catch (DefinitionParameterException e) {
            e.printStackTrace();
        } catch (NoBeanDefFoundException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void get_all_definition_from_current_scope_and_linked_scopes() throws ScopeAlreadyCreatedException, NoScopeDefFoundException, DefinitionParameterException, NoBeanDefFoundException, ClosedScopeException {
        Koin koin = KoinApplication.koinApplication(new KoinAppDeclaration() {
            @Override
            public void invoke(org.koin.core.KoinApplication koinApplication) {
                koinApplication.printLogger();
                org.koin.core.module.Module module = Module.module(new ModuleDeclaration() {
                    @Override
                    public void invoke(org.koin.core.module.Module module) {
                        module.scope(Qualifier.named(ScopeType.class), new org.koin.core.module.Module.ScopeSet() {
                            @Override
                            public void invoke(ScopeDSL scopeDSL) {
                                try {
                                    scopeDSL.scoped(Simple.ComponentA.class, new Definition<Simple.ComponentA>() {
                                        @Override
                                        public Simple.ComponentA invoke(Scope scope, DefinitionParameters parameters) {
                                            return new Simple.ComponentA();
                                        }
                                    });
                                } catch (DefinitionOverrideException e) {
                                    e.printStackTrace();
                                }
                            }
                        });

                        module.scope(Qualifier.named(ScopeType2.class), new org.koin.core.module.Module.ScopeSet() {
                            @Override
                            public void invoke(ScopeDSL scopeDSL) {
                                try {
                                    scopeDSL.scoped(Simple.ComponentA.class, new Definition<Simple.ComponentA>() {
                                        @Override
                                        public Simple.ComponentA invoke(Scope scope, DefinitionParameters parameters) {
                                            return new Simple.ComponentA();
                                        }
                                    });
                                } catch (DefinitionOverrideException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                });
                try {
                    koinApplication.modules(module);
                } catch (DefinitionOverrideException e) {
                    e.printStackTrace();
                }
            }
        }).getKoin();

        Scope scope1 = koin.createScope("scope1", Qualifier.named(ScopeType.class), null);
        Scope scope2 = koin.createScope("scope2", Qualifier.named(ScopeType2.class), null);

        scope1.linkTo(scope2);

        List<Simple.ComponentA> all = Arrays.asList(scope1.get(Simple.ComponentA.class),
                scope2.get(Simple.ComponentA.class));
        Assert.assertEquals(scope1.getAll(Simple.ComponentA.class), all);
    }

    @Test
    public void stopping_koin_closes_scopes() throws ScopeAlreadyCreatedException, NoScopeDefFoundException, KoinAppAlreadyStartedException {
        Koin koin = DefaultContextExt.startKoin(new KoinAppDeclaration() {
            @Override
            public void invoke(org.koin.core.KoinApplication koinApplication) {
                koinApplication.printLogger();
                org.koin.core.module.Module module = Module.module(new ModuleDeclaration() {
                    @Override
                    public void invoke(org.koin.core.module.Module module) {
                        module.scope(Qualifier.named(ScopeType.class), new org.koin.core.module.Module.ScopeSet() {
                            @Override
                            public void invoke(ScopeDSL scopeDSL) {
                                try {
                                    scopeDSL.scoped(Simple.ComponentA.class, new Definition<Simple.ComponentA>() {
                                        @Override
                                        public Simple.ComponentA invoke(Scope scope, DefinitionParameters parameters) {
                                            return new Simple.ComponentA();
                                        }
                                    });
                                } catch (DefinitionOverrideException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                });
                try {
                    koinApplication.modules(module);
                } catch (DefinitionOverrideException e) {
                    e.printStackTrace();
                }
            }
        }).getKoin();

        Scope scope1 = koin.createScope("scope1", Qualifier.named(ScopeType.class), null);
        Scope scope2 = koin.createScope("scope2", Qualifier.named(ScopeType.class), null);

        DefaultContextExt.stopKoin();
        Assert.assertTrue(scope1.getClosed());
        Assert.assertTrue(scope2.getClosed());
    }

    @Test
    public void get_definition_from_current_scope_type() throws ScopeAlreadyCreatedException, NoScopeDefFoundException, DefinitionParameterException, NoBeanDefFoundException, ClosedScopeException {
        Koin koin = KoinApplication.koinApplication(new KoinAppDeclaration() {
            @Override
            public void invoke(org.koin.core.KoinApplication koinApplication) {
                org.koin.core.module.Module module = Module.module(new ModuleDeclaration() {
                    @Override
                    public void invoke(org.koin.core.module.Module module) {
                        module.scope(Qualifier.named(ScopeType.class), new org.koin.core.module.Module.ScopeSet() {
                            @Override
                            public void invoke(ScopeDSL scopeDSL) {
                                try {
                                    scopeDSL.scoped(Simple.ComponentA.class, new Definition<Simple.ComponentA>() {
                                        @Override
                                        public Simple.ComponentA invoke(Scope scope, DefinitionParameters parameters) {
                                            return new Simple.ComponentA();
                                        }
                                    });
                                } catch (DefinitionOverrideException e) {
                                    e.printStackTrace();
                                }

                                try {
                                    scopeDSL.scoped(Simple.ComponentB.class, new Definition<Simple.ComponentB>() {
                                        @Override
                                        public Simple.ComponentB invoke(Scope scope, DefinitionParameters parameters) {
                                            try {
                                                return new Simple.ComponentB(scope.get(Simple.ComponentA.class));
                                            } catch (ClosedScopeException e) {
                                                e.printStackTrace();
                                            } catch (DefinitionParameterException e) {
                                                e.printStackTrace();
                                            } catch (NoBeanDefFoundException e) {
                                                e.printStackTrace();
                                            }
                                            return null;
                                        }
                                    });
                                } catch (DefinitionOverrideException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                });
                try {
                    koinApplication.modules(module);
                } catch (DefinitionOverrideException e) {
                    e.printStackTrace();
                }
            }
        }).getKoin();

        Scope scope = koin.createScope("myScope", Qualifier.named(ScopeType.class), null);

        Assert.assertEquals(scope.get(Simple.ComponentB.class).toString(), scope.get(Simple.ComponentB.class).toString());
        Assert.assertEquals(scope.get(Simple.ComponentA.class), ((Simple.ComponentB) scope.get(Simple.ComponentB.class)).a);

    }

    @Test
    public void get_definition_fromCurrent_factory_scope_type() throws ScopeAlreadyCreatedException, NoScopeDefFoundException, DefinitionParameterException, NoBeanDefFoundException, ClosedScopeException {
        Koin koin = KoinApplication.koinApplication(new KoinAppDeclaration() {
            @Override
            public void invoke(org.koin.core.KoinApplication koinApplication) {

                koinApplication.printLogger();

                org.koin.core.module.Module module = Module.module(new ModuleDeclaration() {
                    @Override
                    public void invoke(org.koin.core.module.Module module) {
                        module.scope(Qualifier.named(ScopeType.class), new org.koin.core.module.Module.ScopeSet() {
                            @Override
                            public void invoke(ScopeDSL scopeDSL) {
                                try {
                                    scopeDSL.scoped(Simple.ComponentA.class, new Definition<Simple.ComponentA>() {
                                        @Override
                                        public Simple.ComponentA invoke(Scope scope, DefinitionParameters parameters) {
                                            return new Simple.ComponentA();
                                        }
                                    });
                                } catch (DefinitionOverrideException e) {
                                    e.printStackTrace();
                                }

                                try {
                                    scopeDSL.factory(Simple.ComponentB.class, null, false, new Definition<Simple.ComponentB>() {
                                        @Override
                                        public Simple.ComponentB invoke(Scope scope, DefinitionParameters parameters) {
                                            try {
                                                return new Simple.ComponentB(scope.get(Simple.ComponentA.class));
                                            } catch (ClosedScopeException e) {
                                                e.printStackTrace();
                                            } catch (DefinitionParameterException e) {
                                                e.printStackTrace();
                                            } catch (NoBeanDefFoundException e) {
                                                e.printStackTrace();
                                            }
                                            return null;
                                        }
                                    });
                                } catch (DefinitionOverrideException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                });

                try {
                    koinApplication.modules(module);
                } catch (DefinitionOverrideException e) {
                    e.printStackTrace();
                }
            }
        }).getKoin();

        Scope scope = koin.createScope("myScope", Qualifier.named(ScopeType.class), null);

        Assert.assertNotEquals(scope.get(Simple.ComponentB.class), scope.get(Simple.ComponentB.class));
        Assert.assertEquals(scope.get(Simple.ComponentA.class), ((Simple.ComponentB) scope.get(Simple.ComponentB.class)).a);
    }

    @Test
    public void get_definition_from_current_scope_type_dispatched_modules() throws ScopeAlreadyCreatedException, NoScopeDefFoundException, DefinitionParameterException, NoBeanDefFoundException, ClosedScopeException {
        Koin koin = KoinApplication.koinApplication(new KoinAppDeclaration() {
            @Override
            public void invoke(org.koin.core.KoinApplication koinApplication) {

                org.koin.core.module.Module module1 = Module.module(new ModuleDeclaration() {
                    @Override
                    public void invoke(org.koin.core.module.Module module) {
                        module.scope(Qualifier.named(ScopeType.class), new org.koin.core.module.Module.ScopeSet() {
                            @Override
                            public void invoke(ScopeDSL scopeDSL) {

                            }
                        });
                    }
                });

                org.koin.core.module.Module module2 = Module.module(new ModuleDeclaration() {
                    @Override
                    public void invoke(org.koin.core.module.Module module) {
                        module.scope(Qualifier.named(ScopeType.class), new org.koin.core.module.Module.ScopeSet() {
                            @Override
                            public void invoke(ScopeDSL scopeDSL) {
                                try {
                                    scopeDSL.scoped(Simple.ComponentA.class, new Definition<Simple.ComponentA>() {
                                        @Override
                                        public Simple.ComponentA invoke(Scope scope, DefinitionParameters parameters) {
                                            return new Simple.ComponentA();
                                        }
                                    });
                                } catch (DefinitionOverrideException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                });

                org.koin.core.module.Module module3 = Module.module(new ModuleDeclaration() {
                    @Override
                    public void invoke(org.koin.core.module.Module module) {
                        module.scope(Qualifier.named(ScopeType.class), new org.koin.core.module.Module.ScopeSet() {
                            @Override
                            public void invoke(ScopeDSL scopeDSL) {
                                try {
                                    scopeDSL.scoped(Simple.ComponentB.class, new Definition<Simple.ComponentB>() {
                                        @Override
                                        public Simple.ComponentB invoke(Scope scope, DefinitionParameters parameters) {
                                            try {
                                                return new Simple.ComponentB(scope.get(Simple.ComponentA.class));
                                            } catch (ClosedScopeException e) {
                                                e.printStackTrace();
                                            } catch (DefinitionParameterException e) {
                                                e.printStackTrace();
                                            } catch (NoBeanDefFoundException e) {
                                                e.printStackTrace();
                                            }
                                            return null;
                                        }
                                    });
                                } catch (DefinitionOverrideException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                });

                try {
                    koinApplication.modules(Arrays.asList(module1, module2, module3));
                } catch (DefinitionOverrideException e) {
                    e.printStackTrace();
                }
            }
        }).getKoin();

        Scope scope = koin.createScope("myScope", Qualifier.named(ScopeType.class));
        Assert.assertEquals(scope.get(Simple.ComponentB.class).toString(), scope.get(Simple.ComponentB.class).toString());
        Assert.assertEquals(scope.get(Simple.ComponentA.class), ((Simple.ComponentB) scope.get(Simple.ComponentB.class)).a);
    }

    @Test
    public void get_definition_from_current_scope() throws ScopeAlreadyCreatedException, NoScopeDefFoundException, DefinitionParameterException, NoBeanDefFoundException, ClosedScopeException {
        Koin koin = KoinApplication.koinApplication(new KoinAppDeclaration() {
            @Override
            public void invoke(org.koin.core.KoinApplication koinApplication) {

                org.koin.core.module.Module module = Module.module(new ModuleDeclaration() {
                    @Override
                    public void invoke(org.koin.core.module.Module module) {
                        module.scope(Qualifier.named(scopeName), new org.koin.core.module.Module.ScopeSet() {
                            @Override
                            public void invoke(ScopeDSL scopeDSL) {
                                try {
                                    scopeDSL.scoped(Simple.ComponentA.class, new Definition<Simple.ComponentA>() {
                                        @Override
                                        public Simple.ComponentA invoke(Scope scope, DefinitionParameters parameters) {
                                            return new Simple.ComponentA();
                                        }
                                    });

                                    scopeDSL.scoped(Simple.ComponentB.class, new Definition<Simple.ComponentB>() {
                                        @Override
                                        public Simple.ComponentB invoke(Scope scope, DefinitionParameters parameters) {
                                            try {
                                                return new Simple.ComponentB(scope.get(Simple.ComponentA.class));
                                            } catch (ClosedScopeException e) {
                                                e.printStackTrace();
                                            } catch (DefinitionParameterException e) {
                                                e.printStackTrace();
                                            } catch (NoBeanDefFoundException e) {
                                                e.printStackTrace();
                                            }
                                            return null;
                                        }
                                    });

                                } catch (DefinitionOverrideException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                });

                try {
                    koinApplication.modules(module);
                } catch (DefinitionOverrideException e) {
                    e.printStackTrace();
                }
            }
        }).getKoin();

        Scope scope = koin.createScope("myScope", Qualifier.named(scopeName));
        Assert.assertEquals(scope.get(Simple.ComponentB.class).toString(), scope.get(Simple.ComponentB.class).toString());
        Assert.assertEquals(scope.get(Simple.ComponentA.class), ((Simple.ComponentB) scope.get(Simple.ComponentB.class)).a);
    }

    @Test
    public void get_definition_from_outside_single() throws ScopeAlreadyCreatedException, NoScopeDefFoundException, DefinitionParameterException, NoBeanDefFoundException, ClosedScopeException {
        Koin koin = KoinApplication.koinApplication(new KoinAppDeclaration() {

            @Override
            public void invoke(org.koin.core.KoinApplication koinApplication) {

                koinApplication.printLogger();

                org.koin.core.module.Module module = Module.module(new ModuleDeclaration() {
                    @Override
                    public void invoke(org.koin.core.module.Module module) {
                        try {
                            module.single(Simple.ComponentA.class, new Definition<Simple.ComponentA>() {
                                @Override
                                public Simple.ComponentA invoke(Scope scope, DefinitionParameters parameters) {
                                    return new Simple.ComponentA();
                                }
                            });
                        } catch (DefinitionOverrideException e) {
                            e.printStackTrace();
                        }

                        module.scope(Qualifier.named(scopeName), new org.koin.core.module.Module.ScopeSet() {
                            @Override
                            public void invoke(ScopeDSL scopeDSL) {
                                try {
                                    scopeDSL.scoped(Simple.ComponentB.class, new Definition<Simple.ComponentB>() {
                                        @Override
                                        public Simple.ComponentB invoke(Scope scope, DefinitionParameters parameters) {
                                            try {
                                                return new Simple.ComponentB(scope.get(Simple.ComponentA.class));
                                            } catch (ClosedScopeException e) {
                                                e.printStackTrace();
                                            } catch (DefinitionParameterException e) {
                                                e.printStackTrace();
                                            } catch (NoBeanDefFoundException e) {
                                                e.printStackTrace();
                                            }
                                            return null;
                                        }
                                    });
                                } catch (DefinitionOverrideException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                });

                try {
                    koinApplication.modules(module);
                } catch (DefinitionOverrideException e) {
                    e.printStackTrace();
                }
            }
        }).getKoin();

        Scope scope = koin.createScope("myScope", Qualifier.named(scopeName));

        Assert.assertEquals(scope.get(Simple.ComponentB.class).toString(), scope.get(Simple.ComponentB.class).toString());
        Assert.assertEquals(scope.get(Simple.ComponentA.class), ((Simple.ComponentB) scope.get(Simple.ComponentB.class)).a);
    }

    @Test
    public void get_definition_from_outside_factory() throws ScopeAlreadyCreatedException, NoScopeDefFoundException, DefinitionParameterException, NoBeanDefFoundException, ClosedScopeException {
        Koin koin = KoinApplication.koinApplication(new KoinAppDeclaration() {
            @Override
            public void invoke(org.koin.core.KoinApplication koinApplication) {

                org.koin.core.module.Module module = Module.module(new ModuleDeclaration() {
                    @Override
                    public void invoke(org.koin.core.module.Module module) {
                        try {
                            module.factory(Simple.ComponentA.class, null, false, new Definition<Simple.ComponentA>() {
                                @Override
                                public Simple.ComponentA invoke(Scope scope, DefinitionParameters parameters) {
                                    return new Simple.ComponentA();
                                }
                            });

                            module.scope(Qualifier.named(scopeName), new org.koin.core.module.Module.ScopeSet() {
                                @Override
                                public void invoke(ScopeDSL scopeDSL) {
                                    try {
                                        scopeDSL.scoped(Simple.ComponentB.class, new Definition<Simple.ComponentB>() {
                                            @Override
                                            public Simple.ComponentB invoke(Scope scope, DefinitionParameters parameters) {
                                                try {
                                                    return new Simple.ComponentB(scope.get(Simple.ComponentA.class));
                                                } catch (ClosedScopeException e) {
                                                    e.printStackTrace();
                                                } catch (DefinitionParameterException e) {
                                                    e.printStackTrace();
                                                } catch (NoBeanDefFoundException e) {
                                                    e.printStackTrace();
                                                }
                                                return null;
                                            }
                                        });
                                    } catch (DefinitionOverrideException e) {
                                        e.printStackTrace();
                                    }
                                }
                            });

                        } catch (DefinitionOverrideException e) {
                            e.printStackTrace();
                        }
                    }
                });

                try {
                    koinApplication.modules(module);
                } catch (DefinitionOverrideException e) {
                    e.printStackTrace();
                }
            }
        }).getKoin();

        Scope scope = koin.createScope("myScope", Qualifier.named(scopeName));
        Assert.assertEquals(scope.get(Simple.ComponentB.class).toString(), scope.get(Simple.ComponentB.class).toString());
        Assert.assertNotEquals(scope.get(Simple.ComponentA.class), ((Simple.ComponentB) scope.get(Simple.ComponentB.class)).a);
    }

    @Test
    public void bad_mix_definition_from_a_scope() throws ScopeAlreadyCreatedException, NoScopeDefFoundException {
        Koin koin = KoinApplication.koinApplication(new KoinAppDeclaration() {
            @Override
            public void invoke(org.koin.core.KoinApplication koinApplication) {

                koinApplication.printLogger();

                org.koin.core.module.Module module = Module.module(new ModuleDeclaration() {
                    @Override
                    public void invoke(org.koin.core.module.Module module) {
                        module.scope(Qualifier.named("SCOPE_1"), new org.koin.core.module.Module.ScopeSet() {
                            @Override
                            public void invoke(ScopeDSL scopeDSL) {
                                try {
                                    scopeDSL.scoped(Simple.ComponentA.class, new Definition<Simple.ComponentA>() {
                                        @Override
                                        public Simple.ComponentA invoke(Scope scope, DefinitionParameters parameters) {
                                            return new Simple.ComponentA();
                                        }
                                    });
                                } catch (DefinitionOverrideException e) {
                                    e.printStackTrace();
                                }
                            }
                        });

                        module.scope(Qualifier.named("SCOPE_2"), new org.koin.core.module.Module.ScopeSet() {
                            @Override
                            public void invoke(ScopeDSL scopeDSL) {
                                try {
                                    scopeDSL.scoped(Simple.ComponentB.class, new Definition<Simple.ComponentB>() {
                                        @Override
                                        public Simple.ComponentB invoke(Scope scope, DefinitionParameters parameters) {
                                            try {
                                                return new Simple.ComponentB(scope.get(Simple.ComponentA.class));
                                            } catch (ClosedScopeException e) {
                                                e.printStackTrace();
                                            } catch (DefinitionParameterException e) {
                                                e.printStackTrace();
                                            } catch (NoBeanDefFoundException e) {
                                                e.printStackTrace();
                                            }
                                            return null;
                                        }
                                    });
                                } catch (DefinitionOverrideException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                });

                try {
                    koinApplication.modules(module);
                } catch (DefinitionOverrideException e) {
                    e.printStackTrace();
                }
            }
        }).getKoin();

        Scope scope2 = koin.createScope("myScope2", Qualifier.named("SCOPE_2"));
        try {
            scope2.get(Simple.ComponentB.class);
            Assert.fail();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Test
    public void mix_definition_from_a_scope() throws ScopeAlreadyCreatedException, NoScopeDefFoundException, DefinitionParameterException, NoBeanDefFoundException, ClosedScopeException {
        Koin koin = KoinApplication.koinApplication(new KoinAppDeclaration() {
            @Override
            public void invoke(org.koin.core.KoinApplication koinApplication) {
                org.koin.core.module.Module module = Module.module(new ModuleDeclaration() {
                    @Override
                    public void invoke(org.koin.core.module.Module module) {
                        module.scope(Qualifier.named("SCOPE_1"), new org.koin.core.module.Module.ScopeSet() {
                            @Override
                            public void invoke(ScopeDSL scopeDSL) {
                                try {
                                    scopeDSL.scoped(Simple.ComponentA.class, new Definition<Simple.ComponentA>() {
                                        @Override
                                        public Simple.ComponentA invoke(Scope scope, DefinitionParameters parameters) {
                                            return new Simple.ComponentA();
                                        }
                                    });
                                } catch (DefinitionOverrideException e) {
                                    e.printStackTrace();
                                }
                            }
                        });

                        module.scope(Qualifier.named("SCOPE_2"), new org.koin.core.module.Module.ScopeSet() {
                            @Override
                            public void invoke(ScopeDSL scopeDSL) {
                                try {
                                    scopeDSL.scoped(Simple.ComponentB.class, new Definition<Simple.ComponentB>() {
                                        @Override
                                        public Simple.ComponentB invoke(Scope scope, DefinitionParameters parameters) {
                                            try {
                                                if (parameters.size() > 0) {
                                                    Scope scope1 = parameters.get(0);
                                                    return new Simple.ComponentB(scope1.get(Simple.ComponentA.class));
                                                }
                                            } catch (ClosedScopeException e) {
                                                e.printStackTrace();
                                            } catch (DefinitionParameterException e) {
                                                e.printStackTrace();
                                            } catch (NoBeanDefFoundException e) {
                                                e.printStackTrace();
                                            }
                                            return null;
                                        }
                                    });
                                } catch (DefinitionOverrideException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                });
                try {
                    koinApplication.modules(module);
                } catch (DefinitionOverrideException e) {
                    e.printStackTrace();
                }
            }
        }).getKoin();

        Scope scope1 = koin.createScope("myScope1", Qualifier.named("SCOPE_1"));
        Scope scope2 = koin.createScope("myScope2", Qualifier.named("SCOPE_2"));

        Simple.ComponentB b = scope2.get(Simple.ComponentB.class, null, new ParametersDefinition() {
            @Override
            public DefinitionParameters invoke() {
                try {
                    return DefinitionParameters.parametersOf(scope1);
                } catch (DefinitionParameterException e) {
                    e.printStackTrace();
                }
                return null;
            }
        });

        Simple.ComponentA a = scope1.get(Simple.ComponentA.class);

        Assert.assertEquals(a, b.a);
    }

    @Test
    public void definition_params_for_scoped_definitions() throws ScopeAlreadyCreatedException, NoScopeDefFoundException, DefinitionParameterException, NoBeanDefFoundException, ClosedScopeException {
        Koin koin = KoinApplication.koinApplication(new KoinAppDeclaration() {
            @Override
            public void invoke(org.koin.core.KoinApplication koinApplication) {

                org.koin.core.module.Module module = Module.module(new ModuleDeclaration() {
                    @Override
                    public void invoke(org.koin.core.module.Module module) {
                        module.scope(Qualifier.named("SCOPE_1"), new org.koin.core.module.Module.ScopeSet() {
                            @Override
                            public void invoke(ScopeDSL scopeDSL) {
                                try {
                                    scopeDSL.scoped(Simple.MySingle.class, new Definition<Simple.MySingle>() {
                                        @Override
                                        public Simple.MySingle invoke(Scope scope, DefinitionParameters parameters) {
                                            int i = 0;
                                            if (parameters.size() > 0) {
                                                i = parameters.get(0);
                                            }
                                            return new Simple.MySingle(i);
                                        }
                                    });
                                } catch (DefinitionOverrideException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                });

                try {
                    koinApplication.modules(module);
                } catch (DefinitionOverrideException e) {
                    e.printStackTrace();
                }
            }
        }).getKoin();

        Scope scope1 = koin.createScope("myScope1", Qualifier.named("SCOPE_1"));
        int parameters = 42;
        Simple.MySingle a = scope1.get(Simple.MySingle.class, null, new ParametersDefinition() {
            @Override
            public DefinitionParameters invoke() {
                try {
                    return DefinitionParameters.parametersOf(parameters);
                } catch (DefinitionParameterException e) {
                    e.printStackTrace();
                }
                return null;
            }
        });

        Assert.assertEquals(parameters, a.getId());
    }

    class ScopeType {

    }

    class ScopeType2 {

    }
}
